package com.star.file;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * 文件操作工具类
 * 提供了多种文件读写操作的方法，包括：
 * 1. 不同方式读取文件为byte[]
 * 2. 将byte[]数据写入文件
 * 3. 其他常用文件操作（复制、删除、获取信息等）
 *
 * 输入输出流说明：
 * - InputStream/OutputStream: 字节流，用于处理二进制数据
 * - Reader/Writer: 字符流，用于处理文本数据
 * - FileInputStream/FileOutputStream: 文件字节流
 * - BufferedInputStream/BufferedOutputStream: 缓冲字节流，提高读写效率
 * - ByteArrayInputStream/ByteArrayOutputStream: 字节数组流，用于在内存中操作字节数据
 */
public class FileOperation {

    public static void main(String[] args) {
        // 示例用法
        FileOperation fileOp = new FileOperation();

        try {
            // 1. 读取文件为byte[]
            System.out.println("=== 文件读取示例 ===");
            // 注意：请替换为实际存在的文件路径
            byte[] data = fileOp.readFileToByteArrayNIO("/path/to/your/file.txt");
            System.out.println("读取到的文件大小: " + data.length + " 字节");

            // 2. 将byte[]写入新文件
            System.out.println("\n=== 文件写入示例 ===");
            // 注意：请确保目标路径有写入权限
            fileOp.writeByteArrayToFileNIO(data, "/path/to/output/file_copy.txt");
            System.out.println("文件写入成功");

            // 3. 获取文件信息
            System.out.println("\n=== 文件信息示例 ===");
            String fileInfo = fileOp.getFileInfo("/path/to/your/file.txt");
            System.out.println(fileInfo);

            // 4. 复制文件
            System.out.println("\n=== 文件复制示例 ===");
            fileOp.copyFile("/path/to/your/file.txt", "/path/to/output/file_copy2.txt");
            System.out.println("文件复制成功");

        } catch (IOException e) {
            System.err.println("文件操作失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 方法1: 使用FileInputStream读取文件为byte[]
     * 适用于小到中等大小的文件
     *
     * FileInputStream特点：
     * - 直接从文件系统读取字节数据
     * - 每次调用read()方法都会访问磁盘，效率较低
     * - 适合小文件或需要精确控制读取过程的场景
     *
     * @param filePath 文件路径
     * @return 文件内容的byte数组
     * @throws IOException 读取文件时可能抛出的异常
     */
    public byte[] readFileToByteArray(String filePath) throws IOException {
        File file = new File(filePath);

        // 检查文件是否存在
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在: " + filePath);
        }

        // 创建FileInputStream
        try (FileInputStream fis = new FileInputStream(file)) {
            // 创建与文件大小相同的byte数组
            byte[] data = new byte[(int) file.length()];

            // 读取文件内容到byte数组
            fis.read(data);

            return data;
        }
    }

    /**
     * 方法2: 使用BufferedInputStream读取文件为byte[]
     * 适用于大文件，通过缓冲提高读取效率
     *
     * BufferedInputStream特点：
     * - 在FileInputStream基础上增加了缓冲区
     * - 减少磁盘访问次数，提高读取效率
     * - 默认缓冲区大小为8192字节(8KB)
     * - 适合大文件读取
     *
     * @param filePath 文件路径
     * @return 文件内容的byte数组
     * @throws IOException 读取文件时可能抛出的异常
     */
    public byte[] readFileToByteArrayWithBuffer(String filePath) throws IOException {
        File file = new File(filePath);

        // 检查文件是否存在
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在: " + filePath);
        }

        // 使用BufferedInputStream提高读取效率
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[8192]; // 8KB缓冲区
            int bytesRead;

            // 循环读取直到文件末尾
            while ((bytesRead = bis.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }

            return baos.toByteArray();
        }
    }

    /**
     * 方法3: 使用Java NIO读取文件为byte[]
     * 现代Java推荐的方式，代码更简洁
     *
     * Java NIO (New IO) 特点：
     * - JDK 1.4引入的新IO API
     * - 基于通道(Channel)和缓冲区(Buffer)进行操作
     * - 支持非阻塞IO和内存映射文件
     * - Files.readAllBytes()方法简单易用，一行代码完成读取
     *
     * @param filePath 文件路径
     * @return 文件内容的byte数组
     * @throws IOException 读取文件时可能抛出的异常
     */
    public byte[] readFileToByteArrayNIO(String filePath) throws IOException {
        Path path = Paths.get(filePath);
        return Files.readAllBytes(path);
    }

    /**
     * 方法1: 使用FileOutputStream将byte[]写入文件
     * 基础的文件写入方法
     *
     * FileOutputStream特点：
     * - 直接向文件系统写入字节数据
     * - 每次调用write()方法都可能触发磁盘写入，效率较低
     * - 适合小文件或需要精确控制写入过程的场景
     *
     * @param data     要写入的字节数据
     * @param filePath 目标文件路径
     * @throws IOException 写入文件时可能抛出的异常
     */
    public void writeByteArrayToFile(byte[] data, String filePath) throws IOException {
        // 创建目标文件对象
        File file = new File(filePath);

        // 如果父目录不存在，则创建
        File parentDir = file.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        // 使用FileOutputStream写入数据
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(data);
        }
    }

    /**
     * 方法2: 使用BufferedOutputStream将byte[]写入文件
     * 适用于大文件，通过缓冲提高写入效率
     *
     * BufferedOutputStream特点：
     * - 在FileOutputStream基础上增加了缓冲区
     * - 减少磁盘写入次数，提高写入效率
     * - 默认缓冲区大小为8192字节(8KB)
     * - 适合大文件写入
     *
     * @param data     要写入的字节数据
     * @param filePath 目标文件路径
     * @throws IOException 写入文件时可能抛出的异常
     */
    public void writeByteArrayToFileWithBuffer(byte[] data, String filePath) throws IOException {
        // 创建目标文件对象
        File file = new File(filePath);

        // 如果父目录不存在，则创建
        File parentDir = file.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        // 使用BufferedOutputStream提高写入效率
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
            bos.write(data);
        }
    }

    /**
     * 方法3: 使用Java NIO将byte[]写入文件
     * 现代Java推荐的方式，代码更简洁
     *
     * Java NIO写入特点：
     * - Files.write()方法简单易用
     * - 自动处理资源管理
     * - 可以指定写入选项（如追加模式等）
     *
     * @param data     要写入的字节数据
     * @param filePath 目标文件路径
     * @throws IOException 写入文件时可能抛出的异常
     */
    public void writeByteArrayToFileNIO(byte[] data, String filePath) throws IOException {
        Path path = Paths.get(filePath);

        // 创建父目录（如果不存在）
        Path parentDir = path.getParent();
        if (parentDir != null) {
            Files.createDirectories(parentDir);
        }

        // 写入数据
        Files.write(path, data);
    }

    /**
     * 复制文件
     *
     * Files.copy()特点：
     * - Java NIO提供的高效文件复制方法
     * - 可以指定复制选项（如覆盖已存在文件等）
     * - 性能优于手动读写方式
     *
     * @param sourcePath 源文件路径
     * @param targetPath 目标文件路径
     * @throws IOException 复制文件时可能抛出的异常
     */
    public void copyFile(String sourcePath, String targetPath) throws IOException {
        Path source = Paths.get(sourcePath);
        Path target = Paths.get(targetPath);

        // 创建目标文件的父目录（如果不存在）
        Path targetParent = target.getParent();
        if (targetParent != null) {
            Files.createDirectories(targetParent);
        }

        // 复制文件，如果目标文件已存在则覆盖
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 获取文件信息
     *
     * File类提供了丰富的文件属性获取方法：
     * - getName(): 获取文件名
     * - getAbsolutePath(): 获取绝对路径
     * - length(): 获取文件大小
     * - isFile()/isDirectory(): 判断是文件还是目录
     * - lastModified(): 获取最后修改时间
     *
     * @param filePath 文件路径
     * @return 包含文件信息的字符串
     */
    public String getFileInfo(String filePath) {
        File file = new File(filePath);

        if (!file.exists()) {
            return "文件不存在: " + filePath;
        }

        StringBuilder info = new StringBuilder();
        info.append("文件名: ").append(file.getName()).append("\n");
        info.append("文件路径: ").append(file.getAbsolutePath()).append("\n");
        info.append("文件大小: ").append(file.length()).append(" 字节\n");
        info.append("是否为文件: ").append(file.isFile()).append("\n");
        info.append("是否为目录: ").append(file.isDirectory()).append("\n");
        info.append("最后修改时间: ").append(new java.util.Date(file.lastModified())).append("\n");

        return info.toString();
    }

    /**
     * 删除文件
     *
     * File.delete()特点：
     * - 简单直接的删除方法
     * - 返回boolean值表示删除成功与否
     * - 删除后文件不可恢复，请谨慎使用
     *
     * @param filePath 文件路径
     * @return 删除成功返回true，否则返回false
     */
    public boolean deleteFile(String filePath) {
        File file = new File(filePath);
        return file.delete();
    }

    /**
     * 检查文件是否存在
     *
     * File.exists()特点：
     * - 快速检查文件或目录是否存在
     * - 不会抛出异常，即使路径无效也返回false
     * - 是文件操作前的重要验证步骤
     *
     * @param filePath 文件路径
     * @return 存在返回true，否则返回false
     */
    public boolean fileExists(String filePath) {
        File file = new File(filePath);
        return file.exists();
    }
}
